#include "utils.h"
#include <stdlib.h>
#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <time.h>

WORD n2c(char n) {
	switch (n){
		case 'a': case 'A':
			return (WORD)0;
		case 'c': case 'C':
			return (WORD)1;
		case 'g': case 'G':
			return (WORD)2;
		case 't': case 'T':
			return (WORD)3;
		}
	return ERROR;
	}

/*

FILE *open_seqfile(char *dir, char *prefix, int fileNumber) {
	char filename[MAX_PATH_LENGTH] = {0};
	FILE *seqfile = NULL;
	sprintf(filename,"%s%s_%d", dir, prefix, fileNumber);				
	if ((seqfile = fopen(filename,"r")) == NULL) {
		fprintf(stderr, "Cannot open sequence file: %s\n", filename);
		exit(1);
		}
	return seqfile;
	}

void readseq(FILE *seqfile, char *buffer, int startPos, int length) {
	fseek(seqfile, startPos, SEEK_SET);
	//fprintf(stderr, "fseek: %d\n", seqs[i]->occurences[0].startPos);
	if ( fread(buffer, sizeof(char), length, seqfile) != length) {
		fprintf(stderr, "readseq: Cannot read from seqfile!\n");
		exit(1);
		}
	}


int validateMatch(char *seq1,  char *seq2, int length) {
	int k;
	for(k = 0; k < length; k++) {
		if(tolower(seq1[k]) != tolower(seq2[k])) {
			return 0;
		}
	}
	return 1;
}
*/

// returns the length of the bit sequence given the real length of the dna
int blen(int n) {
	return (n % BASES_PER_WORD == 0 ? 0 : 1) + n / BASES_PER_WORD;
	}	

	

void count_sequences(char *fastaFile, int *total_sequences, int *total_bitseq_length) {
	
	char line[MAXLINE] = {0};	
	int qlen = 0;
	FILE *file = fopen((const char*)fastaFile,"r");
	
	/*Check for validity of the file.*/
	if(file == 0) {
		fprintf(stderr,"can't open file: %s.\n", fastaFile);		
		*total_sequences = -1;
		*total_bitseq_length = -1;
		return;
	}	
	int tseq = 0;
	int tbitseq = 0;
	/* calculate the number of fasta sequences in the file */
	fprintf(stderr,"counting sequences\n");
	start_watch();
	while ( fgets (line, sizeof line, file) != NULL ) {
		if (line[0] == '>') { 
			tseq ++;
		} else {
			qlen = strlen(line);
			if (line[qlen-1] == '\n') { line[qlen-1] = 0; qlen--; }
			tbitseq += blen(qlen);
		}
	}
	fclose(file);	
	fprintf(stderr,"%d sequences, %d bitseq length | ", tseq, tbitseq);
	
	stop_watch();
	*total_sequences = tseq;
	*total_bitseq_length = tbitseq;
	}


	
	
void fasta2seq(char *filename, 
							 SEQUENCE ***_seqs, 
							 SEQUENCE **_seqdata, 
							 WORD **_bitseqdata, 
							 int *total_sequences, 
							 int *total_bitseq_length) {
	// sequences is a pointer to an array of sequences
	char line[MAXLINE] = {0};
	count_sequences(filename, total_sequences, total_bitseq_length);
	
	*_seqs = NULL;
	
	if (*total_sequences == -1) { 
		return; 
	}
	
	FILE *file = fopen((const char*)filename,"r");
	
	/* Check for validity of the file. */
	if(file == NULL) {
		*total_sequences = -1;
		fprintf(stderr,"can't open file: %s.\n", filename);
		return;
	}
	
	SEQUENCE **seqs = (SEQUENCE **)malloc((*total_sequences)*sizeof(SEQUENCE *));
	SEQUENCE *seqdata = (SEQUENCE *)malloc((*total_sequences)*sizeof(SEQUENCE));
	WORD *bitseqdata = (WORD *)calloc(*total_bitseq_length, sizeof(WORD));
	if (seqs == NULL || seqdata == NULL || bitseqdata == NULL){
		fprintf(stderr, "Not enough memory!\n");
		}
	start_watch();
	/* read and convert the sequences */
	fprintf(stderr,"reading sequences\n");
	
	int seq_no = 0;			
	long seq_header_position = -1;
	int bitseq_index = 0;
	int i = 0;
	int byte_index = 0;
	int in_byte_index = 0;
	while ( fgets (line, sizeof line, file) != NULL ) {
		//printf("%s", line);
		// record the header position in the file 
		if (line[0] == '>') { 
			seq_header_position = ftell(file) - strlen(line); 
			continue; } 
		
		int qlen = strlen(line);
		if (line[qlen-1] == '\n') { line[qlen-1] = 0; qlen--; }
		
		// init the sequence
		seqs[seq_no] = &seqdata[seq_no];
		seqs[seq_no]->id = seq_header_position;
		seqs[seq_no]->bitseq = &bitseqdata[bitseq_index];
		seqs[seq_no]->real_length = qlen;
			
		for (i = 0; i < qlen; i++) {
			byte_index = i / BASES_PER_WORD;
			in_byte_index = (BITS_PER_WORD - BITS_PER_BASE) - BITS_PER_BASE*(i % BASES_PER_WORD);
			
			WORD c = n2c(line[i]) << in_byte_index;
			
			seqs[seq_no]->bitseq[byte_index] += c;
			
			//printf("%c: %d %d %d %u %u\n",line[i], bitseq_index, byte_index, in_byte_index, c, bitseqdata[bitseq_index + byte_index]);
			
			}
		
		
		seq_no ++;
		bitseq_index += blen(qlen);
		}	 
	fclose(file);      	
	fprintf(stderr,"reading finished | ");
	stop_watch();
	
	*_seqs = seqs;
	*_seqdata = seqdata;
	*_bitseqdata = bitseqdata;
	}



char c2n(WORD c) {
	switch(c) {
		case 0:
			return 'a';
		case 1:
			return 'c';
		case 2:
			return 'g';
		case 3:
			return 't';
		}
	return 'X';
	}


void seq2buffer(SEQUENCE *seq, char *buf) {
	int i, j, dna_index = -1;
	int bytes_length = blen(seq->real_length);
	for (i = 0; i < bytes_length; i++) {
		for (j = 0; j < BASES_PER_WORD ; j++) {
			dna_index = i*BASES_PER_WORD + j;
			if (dna_index >= seq->real_length) { 
				break; 
			}
			buf[dna_index] = c2n(BCHAR(seq->bitseq[i],j));
			}	
		}
	buf[dna_index] = 0;
	}


void bitseq2char(WORD *bitseq, int seq_real_length, char *charseq) {
	int i, j, dna_index = -1;
	int bytes_length = blen(seq_real_length);
	for (i = 0; i < bytes_length; i++) {
		for (j = 0; j < BASES_PER_WORD ; j++) {
			dna_index = i*BASES_PER_WORD + j;
			if (dna_index >= seq_real_length) { 
				break; 
			}
			charseq[dna_index] = c2n(BCHAR(bitseq[i],j));
			}	
		}
	charseq[dna_index] = 0;		
	}
		



time_t START_TIME;
void start_watch() { START_TIME = time(NULL); } 
void stop_watch() { fprintf (stderr, "%ld seconds\n", time(NULL) - START_TIME); }
